<?php


namespace app\command;


use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Workerman\Connection\AsyncTcpConnection;
use Workerman\Worker;

class IntranetPenetrationCommand extends \Symfony\Component\Console\Command\Command
{

    protected static $defaultName = 'config:intranet';
    protected static $defaultDescription = '内网穿透服务配置';
    protected function configure()
    {
        $this
            // 命令的名称 ("php console_command" 后面的部分)
            //->setName('model:create')
            // 运行 "php console_command list" 时的简短描述
            ->setDescription('Create new model')
            // 运行命令时使用 "--help" 选项时的完整命令描述
            ->setHelp('This command allow you to create models...')
            // 配置一个参数
            ->addArgument('name', InputArgument::REQUIRED, 'what\'s model you want to create ?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('内网穿透服务配置：');
        $worker = new Worker();

        $worker->count = config('intranet.client_worker_count');
        $worker->onWorkerStart = function($worker)
        {
            $con = new AsyncTcpConnection('tcp://'.config('intranet.server_ip').':'.config('intranet.server_port'));//连接服务端

            $con->onConnect = function($connection) {
                echo "connection server success\n";
                global $config;
                $connection->send($config['secret']);//注册代理
            };
            $con->onMessage = function($connection, $buffer) {
                // $addr = "docker.for.mac.host.internal";
                global $config;
                $addr =  $config['local_address'];
                echo "$addr\n";
                $buffer = str_replace('Host: '.$config['server_ip'],'Host: '.$addr,$buffer);//将HOST设为目标值
                echo "$buffer\n";

                // echo "$url_data";
                // Async TCP connection.
                $remote_connection = new AsyncTcpConnection("tcp://$addr");

                $remote_connection->onConnect = function($remote_connection)use($buffer){
                    $remote_connection->send($buffer);
                };
                $remote_connection->onMessage = function($remote_connection,$msg)use($connection){
                    $connection->send($msg);
                };
                $remote_connection->onClose = function($remote_connection){
                    echo "remote_connection closed\n";
                };
                $remote_connection->onBufferFull  = function ($remote_connection) use ($connection) {
                    $connection->pauseRecv();
                };
                $remote_connection->onBufferDrain = function ($remote_connection) use ($connection) {
                    $connection->resumeRecv();
                };
                $connection->onBufferFull  = function ($connection) use ($remote_connection) {
                    $remote_connection->pauseRecv();
                };
                $connection->onBufferDrain = function ($connection) use ($remote_connection) {
                    $remote_connection->resumeRecv();
                };
                $remote_connection->connect();

            };

            $con->onClose = function($con) {
                // 如果连接断开，则在1秒后重连
                global $config;
                echo "connection server closed\n";
                if($config['client_close_re_connect']){//断线重连
                    $con->reConnect($config['after_re_connect']);
                }
            };
            $con->connect();
        };
        $worker_service = new Worker('tcp://0.0.0.0:'.config('intranet.server_port'));//中间的通道
        $worker_service->count = 1;

        $worker_service->onWorkerStart = function($worker){
        };
        $worker_service->onConnect = function($connection){
        };

        $worker_service->onMessage = function  ($connection, $msg){

            if(!isset($connection->is_proxy)){//初始化代理参数
                $connection->is_proxy = false;
                $connection->is_busy = false;
                $connection->proxy_connect = null;
                echo "proxy:{$connection->id} params init success\n";
            }

            if($connection->is_proxy&&$connection->is_busy){//说明正在代理
                echo "proxy:{$connection->id}-{$connection->proxy_connect->id}\n\n";
                $connection->proxy_connect->send($msg);
                return ;
            }
            $secret = substr($msg,0,11);
            if ($secret == config('intranet.secret')) {//说明是客户端注册
                $connection->is_proxy = true; //标记该连接是代理连接
            } else {//用户请求
                if(!$connection->is_proxy&&$connection->proxy_connect){//该用户连接已有代理了直接复用
                    $connection->proxy_connect->send($msg);
                    return ;
                }
                $proxy= null;//寻找是否有代理连接
                foreach($connection->worker->connections as $proxyConnect)
                {
                    if($proxyConnect->is_proxy){
                        if(!$proxyConnect->is_busy){
                            $proxyConnect->is_busy = true;
                            $proxy = $proxyConnect;
                            $connection->proxy_connect = $proxy;//将代理连接放到自身中

                            break;
                        }else{
                            echo "proxy:{$proxyConnect->id} the proxyConnect is busy\n";
                        }
                    }
                }

                if(empty($proxy)){//代理连接用完了，直接404
                    $connection->send("HTTP/1.1 404 Connection Established\r\n\r\n");
                    $connection->close();
                }else{
                    $proxy->proxy_connect = $connection;
                    $proxy->send($msg);
                    $connection->onClose = function($connection)use($proxy){//用户连接关闭后，空出代理连接
                        echo "user connect closed\n";
                        $proxy->is_busy = false;
                        $proxy->proxy_connect = null;
                        $connection->proxy_connect = null;
                    };
                    // $connection->close();
                    $proxy->onBufferFull  = function ($proxy) use ($connection) {
                        $connection->pauseRecv();
                    };
                    $proxy->onBufferDrain = function ($proxy) use ($connection) {
                        $connection->resumeRecv();
                    };
                    $connection->onBufferFull  = function ($connection) use ($proxy) {
                        $proxy->pauseRecv();
                    };
                    $connection->onBufferDrain = function ($connection) use ($proxy) {
                        $proxy->resumeRecv();
                    };
                }
            }
        };
        $worker_service->onClose = function($connection){//代理连接关闭后走这个
            echo "proxy connection closed:{$connection->id}\n";
        };
        Worker::runAll();
        return self::SUCCESS;
    }
}
